home *** CD-ROM | disk | FTP | other *** search
- Subject: v08i078: Public-domain implementations of cut(1) and paste(1)
- Newsgroups: mod.sources
- Approved: mirror!rs
-
- Submitted by: pyramid!ptsfa!ptsfc!jgw (John Weald)
- Mod.sources: Volume 8, Issue 78
- Archive-name: cut+paste
-
- Here is a verion of AT&T's cut and paste, it was not written from the source.
- Cheers!
- John Weald
- {ihnp4, pyramid}!ptsfa!ptsfc!jgw
-
- [ This also includes another re-implementaion of getopt. --r$ ]
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line,
- # then unpack it by saving it in a file and typing "sh file".
- # If all goes well, you will see the message "End of shell archive."
- # Contents: README cut.1 cut.c getopt.c makefile paste.1 paste.c
- # spaste.c
- PATH=/bin:/usr/bin:/usr/ucb; export PATH
- echo shar: extracting "'README'" '(968 characters)'
- if test -f 'README' ; then
- echo shar: will not over-write existing file "'README'"
- else
- sed 's/^X//' >README <<'@//E*O*F README//'
- XThis is a public domain version of AT&T's cut and paste commands. Included is
- Xyet another version of getopt(3). If you already have a version then
- Xchange the makefile.
- X
- XThe software has been tested on both 4.2BSD (CCI Power 6/32 aka Sperry 7000/40)
- Xand SVR2 (3b2/400). It is currently in production mode on 4.2.
- X
- XThe only known difference is that this cut does not require the list to be in
- Xassending order. e.g.
- X cut -f4,2,1 x <=> cut -f1,2,4 x
- X
- XWhen a range is specified then the range must be in order e.g.
- X cut -f3-2
- Xwill cause an error message.
- X
- XDepending upon your point of view this may or may not be a
- Xproblem.
- X
- XError messages are a little more helpful than in SVR1, in particular they
- Xtell you what the limits are for line lenghts etc.
- X
- XFeel free to change the software, send any bug reports to
- X {ihnp4, pyramid}!ptsfa!ptsfc!ccm
- Xsince I am off the unix mail until the next assignment!!
- X
- XHave fun,
- X John Weald
- X AGS Computers, Inc.
- X 415-463-8711
- X
- @//E*O*F README//
- if test 968 -ne "`wc -c <'README'`"; then
- echo shar: error transmitting "'README'" '(should have been 968 characters)'
- fi
- fi # end of overwriting check
- echo shar: extracting "'cut.1'" '(2652 characters)'
- if test -f 'cut.1' ; then
- echo shar: will not over-write existing file "'cut.1'"
- else
- sed 's/^X//' >cut.1 <<'@//E*O*F cut.1//'
- X.if t .ds ' \h@.05m@\s+4\v@.333m@\'\v@-.333m@\s-4\h@.05m@
- X.if n .ds ' '
- X.if t .ds ` \h@.05m@\s+4\v@.333m@\`\v@-.333m@\s-4\h@.05m@
- X.if n .ds ` `
- X.TH CUT 1
- X.SH NAME
- Xcut \- cut out selected fields of each line of a file
- X.SH SYNOPSIS
- X\fBcut \-c\fP\^list [\|file1 file2 ...]
- X.br
- X\fBcut \-f\fP\^list [\fB\-d\fP\|char\|] [\fB\-s\fP] [\|file1 file2 ...]
- X.SH DESCRIPTION
- XUse
- X.I cut\^
- Xto cut out columns from a table or
- Xfields from each line of a file; in data base parlance, it implements
- Xthe projection of a relation.
- XThe fields as specified by
- X.I list\^
- Xcan be fixed length,
- Xi.e., character positions as on a punched card
- X(\fB\-c\fP option) or the length can vary from line to line
- Xand be marked with a field delimiter character like
- X.I tab\^
- X(\fB\-f\fP option).
- X.I Cut\^
- Xcan be used as a filter;
- Xif no files are given, the standard input is used.
- X.PP
- XThe meanings of the options are:
- X.br
- X.TP "\w'\-d\ char\ \ 'u"
- X.I list\^
- XA comma-separated
- Xlist of integer field numbers,
- Xwith optional \fB\-\fP to indicate ranges
- Xas in the
- X.B \-o
- Xoption of
- X.IR nroff / troff
- Xfor page ranges;
- Xe.g.,
- X.BR 1,4,7 ;
- X.BR 1\-3,8 ;
- X.B \-5,10
- X(short for \fB1\-5,10\fP); or
- X.B 3\-
- X(short for third through last field).
- X.TP
- X\fB\-c\fP\^\fIlist\fP
- XThe
- X.I list\^
- Xfollowing
- X.B \-c
- Xspecifies character
- Xpositions (e.g.,
- X.B \-c1\-72
- Xwould pass the first 72 characters
- Xof each line).
- X.TP
- X\fB\-f\fP\^\fIlist\fP
- XThe \fIlist\fP following
- X.B \-f
- Xis a list of fields
- Xassumed to be separated in the file by a delimiter character (see
- X.B \-d
- X);
- Xe.g.,
- X.B \-f1,7
- Xcopies the first and seventh field only.
- XLines with no field delimiters will be passed through intact (useful
- Xfor table subheadings), unless
- X.B \-s
- Xis specified.
- X.TP
- X\fB\-d\fP\^\fIchar\fP
- XThe character following
- X.B \-d
- Xis the field delimiter
- X(\c
- X.B \-f
- Xoption only).
- XDefault is
- X.IR tab .
- XSpace or other characters with special meaning to the shell must be quoted.
- X.TP
- X.B \-s
- XSuppresses lines with no delimiter characters in case of
- X.B \-f
- Xoption.
- XUnless specified, lines with no delimiters will be passed through untouched.
- X.PP
- XEither the
- X.B \-c
- Xor
- X.B \-f
- Xoption must be specified.
- X.SH HINTS
- XUse
- X.IR grep (1)
- Xto make horizontal ``cuts''
- X(by context) through a file, or
- X.IR paste (1)
- Xto put files together column-wise
- X(i.e., horizontally).
- XTo reorder columns in a table, use
- X.I cut\^
- Xand
- X.IR paste .
- X.SH EXAMPLES
- X.TP 2.25i
- Xcut \-d: \-f1,5 /etc/passwd
- Xmapping of user \s-1ID\s0s to names
- X.TP
- Xname=\*`who am i | cut \-f1 \-d" "\*`
- Xto set
- X.B name
- Xto current login
- Xname.
- X.SH DIAGNOSTICS
- X.PP
- XError messages may come from getopt(3). All error messages contain limits
- Xfor line and field lenghts.
- X.SH SEE ALSO
- Xgrep(1),
- Xpaste(1).
- Xgetopt(3)
- @//E*O*F cut.1//
- if test 2652 -ne "`wc -c <'cut.1'`"; then
- echo shar: error transmitting "'cut.1'" '(should have been 2652 characters)'
- fi
- fi # end of overwriting check
- echo shar: extracting "'cut.c'" '(4941 characters)'
- if test -f 'cut.c' ; then
- echo shar: will not over-write existing file "'cut.c'"
- else
- sed 's/^X//' >cut.c <<'@//E*O*F cut.c//'
- X/*
- X * This acts the same as SV cut(1), except that the list of numbers
- X * does not have to be assending.
- X *
- X * John Weald
- X */
- X#include <stdio.h>
- X#include <ctype.h>
- X
- X#define MAXLINE 1024 /* The max. length of a line */
- X
- Xextern void exit();
- X
- Xmain(argc, argv)
- Xint argc;
- Xchar *argv[];
- X{
- X extern char *optarg;
- X extern int optind;
- X
- X static int fields[MAXLINE];/* The field markers. True if this field */
- X /* is to be cut, False otherwise */
- X FILE *fp; /* All the input files or stdin */
- X char buf[MAXLINE]; /* The input buffer */
- X int c; /* The command line option */
- X int err = 0; /* True if error in command line */
- X int fflag = 0; /* True if -f on command line */
- X int cflag = 0; /* True if -c on command line */
- X int suppress = 0; /* Suppress lines with no delimitor */
- X char fs = '\t'; /* The field separator */
- X
- X
- X while ((c = getopt(argc, argv, "f:d:c:s")) != EOF)
- X {
- X switch (c)
- X {
- X case 'f':
- X /* By Field */
- X list(fields, optarg);
- X fflag++;
- X if (cflag)
- X err++;
- X break;
- X
- X case 'c':
- X /* By character */
- X list(fields, optarg);
- X /* Implied suppress */
- X suppress++;
- X cflag++;
- X if (fflag)
- X err++;
- X break;
- X
- X case 'd':
- X /* A new field spererator */
- X fs = *optarg;
- X break;
- X
- X case 's':
- X suppress++;
- X break;
- X
- X default:
- X prusage();
- X }
- X }
- X
- X if (!cflag && !fflag)
- X {
- X fprintf(stderr, "Must have one of -f or -c\n");
- X err++;
- X }
- X if (err)
- X prusage();
- X
- X
- X /*
- X * Loop on all the files.
- X */
- X do {
- X if (optind == argc)
- X fp = stdin;
- X else if ((fp = fopen(argv[optind], "r")) == (FILE *)NULL)
- X {
- X fprintf(stderr, "Failed to open file %s\n",
- X argv[optind]);
- X exit(1);
- X }
- X
- X /*
- X * Loop on all lines in the file.
- X */
- X while (fgets(buf, sizeof(buf), fp) != (char *)NULL)
- X {
- X cut(buf, fields, fs, suppress, cflag);
- X }
- X (void)fclose(fp);
- X } while (++optind < argc);
- X
- X exit(0);
- X/* NOTREACHED */
- X}
- X
- X/*
- X * Cut the line. This handles both character and field cutting.
- X * For character cutting the f array gives character positions, for
- X * fields it gives the field number. It must be indexed by either the
- X * character number or the field number.
- X */
- Xcut(in, f, fs, sup, c_or_f)
- Xregister char *in; /* The input line */
- Xint f[]; /* The field cutting flags */
- Xchar fs; /* The field seperator */
- Xint sup; /* Suppress lines with no-delimitor? */
- Xint c_or_f; /* Cut by char. (true), or field (false)*/
- X{
- X char obuf[MAXLINE]; /* Output buffer */
- X register char *optr = obuf;
- X register int i; /* Character count */
- X register int fld; /* The field count */
- X char *instart = in; /* To print lines with no delimiters */
- X
- X for (fld = 0, i = 0; i < MAXLINE; i++)
- X {
- X if (*in == '\n')
- X {
- X /* End of the line */
- X
- X *optr = '\0';
- X /* Any thing to cut? */
- X if (optr != obuf)
- X {
- X /* Get ride of trailing seperator */
- X if (*(optr - 1) == fs)
- X *(optr - 1) = '\0';
- X puts(obuf);
- X }
- X else if (!sup)
- X printf(instart);
- X return;
- X }
- X
- X if (f[c_or_f ? i : fld])
- X {
- X *optr++ = *in;
- X }
- X
- X /* End of field? */
- X if (*in++ == fs)
- X fld++;
- X }
- X
- X fprintf(stderr, "Line too long, maximum length is %d\n", MAXLINE);
- X exit(1);
- X}
- X
- X/*
- X * Parse the list argument. The format is:
- X * n,n
- X * where n is either a number or a range of numbers in the format
- X * m-l
- X * m or l may be absent, indicating the start or end of the lines respectivly.
- X * Numbers must be in increasing order for m-l format, but not for n,n.
- X * Field numbers start at 1, but index into fields array starts at 0.
- X *
- X */
- Xlist(f, l)
- Xint f[]; /* The fields */
- Xchar *l; /* The list */
- X{
- X int range = 0; /* True if m-l format */
- X int low, high; /* the low and high numbers in a m-l pair*/
- X int i;
- X
- X low = high = 0;
- X
- X while (1)
- X {
- X switch(*l)
- X {
- X case '\0':
- X /* Is it m-<nothing>EOL? */
- X if (range)
- X {
- X /* Select rest of fields */
- X for(i = low - 1; i < MAXLINE; i++)
- X f[i]++;
- X }
- X else
- X f[low-1]++;
- X return;
- X
- X case ',':
- X l++;
- X if (!range)
- X f[low-1]++;
- X range = 0;
- X low = 1;
- X break;
- X
- X case '-':
- X l++;
- X range++;
- X /* Is it m-<nothing> */
- X if (isdigit((int)*l))
- X {
- X high = atoi(l);
- X /* Skip the digits */
- X while (isdigit((int) *l))
- X l++;
- X }
- X else
- X high = MAXLINE;
- X
- X /* Is the range the correct way around? */
- X if (low > high)
- X {
- X fprintf(stderr, "Bad c/f list: %d > %d\n",
- X low, high);
- X exit(1);
- X }
- X /* Set the field flags for the range */
- X for(i = low - 1; i < high; i++)
- X f[i]++;
- X break;
- X
- X default:
- X /* either a number or an error */
- X if (!isdigit((int) *l))
- X {
- X fprintf(stderr, "Bad c/f list at %s\n", l);
- X exit(1);
- X }
- X low = atoi(l);
- X if (low == 0)
- X {
- X fprintf(stderr, "Fields start at 1 not 0\n");
- X exit(1);
- X }
- X /* Skip the digits */
- X while (isdigit((int) *l))
- X l++;
- X break;
- X }
- X }
- X}
- X
- Xprusage()
- X{
- X fprintf(stderr, "cut [-d<delimitor>] [-s] -c<list>|-f<list> [files]\n");
- X exit(1);
- X}
- @//E*O*F cut.c//
- if test 4941 -ne "`wc -c <'cut.c'`"; then
- echo shar: error transmitting "'cut.c'" '(should have been 4941 characters)'
- fi
- fi # end of overwriting check
- echo shar: extracting "'getopt.c'" '(3739 characters)'
- if test -f 'getopt.c' ; then
- echo shar: will not over-write existing file "'getopt.c'"
- else
- sed 's/^X//' >getopt.c <<'@//E*O*F getopt.c//'
- X/*
- X * getopt(), a verson of getopt for those who do not have it and do not
- X * want to steal the source from those that do.
- X *
- X * Same as getopt(3).
- X * Returns the next option letter in argv that matches a letter in optstr.
- X * Options are no longer parsed if the special option '--' is found
- X * or an argument that does not start in '-'.
- X * The global optind is set to the next index in argv to be processed.
- X * The global optarg is set to the argument, if the option has one.
- X * The global opterr can be set true if error messages are to be printed
- X * on the standard error file, or false if no message to be printed.
- X *
- X * ARGUMENTS:
- X * argc, argv - the argument count, and argument list
- X * optstr - the list of valid options. The character ":" following
- X * an option letter indicates that this option must have an
- X * argument. For example "abc:". This implies that the -:
- X * is not a valid option.
- X *
- X * RETURNS:
- X * Returns the next option letter, or EOF when all done. If an error
- X * encountered then the character '?' is returned.
- X *
- X * John Weald
- X */
- X#include <stdio.h>
- X
- X/*
- X * Index into error array.
- X */
- X#define BAD_OPT 0 /* option letter not in optstr */
- X#define MIS_ARG 1 /* option must have an argument */
- X
- Xchar *optarg;
- Xint optind = 1; /* argv[0] is program name */
- Xint opterr = 1; /* If true print error message */
- X
- X/*
- X *
- X * The basic data structures are optind, and the pointer "p."
- X * optind keeps track of the next index into argv to parse arguments.
- X * p is used to walk along the argv items looking for option letters or
- X * arguments, when it is NULL the next argv must be used .
- X * p is always left pointing to the previous option or NULL.
- X * Consider the three equivalent valid argv's:
- X * 1 2 3
- X * -a -b eric
- X * -ab eric
- X * -aberic
- X *
- X */
- X
- Xint
- Xgetopt(argc, argv, optstr)
- Xint argc;
- Xchar *argv[];
- Xchar *optstr; /* The list of valid options */
- X{
- X extern void err(); /* Forward reference */
- X
- X static char *p = (char *)NULL;
- X
- X /*
- X * parsed all the options in this argv[]?
- X */
- X if (p == NULL || *++p == '\0' )
- X {
- X if (optind == argc)
- X return(EOF);
- X p = argv[optind];
- X
- X /* a '-' by itself is not an option (e.g. see paste(1)) */
- X if (*p++ != '-' || *p == '\0')
- X return(EOF);
- X
- X /* '--' marks the end of the option list. */
- X if (*p == '-')
- X {
- X optind++;
- X return(EOF);
- X }
- X }
- X
- X optind++;
- X /*
- X * Look for a valid option
- X */
- X while (*p != *optstr)
- X {
- X if (*optstr == '\0')
- X {
- X /* Reached end of optstr, option not there */
- X err(argv[0], BAD_OPT, *p);
- X return((int)'?');
- X }
- X if (*++optstr == ':')
- X optstr++;
- X }
- X
- X /* If it does not need an argument then we are done. */
- X if (*(optstr + 1) != ':')
- X return((int)*optstr);
- X
- X /*
- X * If there are more characters in this argv then it must
- X * be the argument.
- X */
- X if (*++p != '\0')
- X {
- X optarg = p;
- X p = (char *)NULL;
- X return((int)*optstr);
- X }
- X
- X /*
- X * It needs an argument, but no more argv's left
- X */
- X if (optind == argc)
- X {
- X err(argv[0], MIS_ARG, *optstr);
- X p = (char *)NULL;
- X return((int)'?');
- X }
- X
- X /*
- X * Must be in next argv.
- X */
- X optarg = argv[optind++];
- X p = (char *)NULL;
- X return((int)*optstr);
- X}
- X
- Xstatic void
- Xerr(a0, e, c)
- Xchar *a0; /* argv[0]. i.e. the program name */
- Xint e;
- Xchar c;
- X{
- X#ifdef NO_STDIO
- X static char *errors[] = {
- X ": Illegal option -- ",
- X ": option requires an argument -- "
- X };
- X static char eend[] = "c\n";
- X
- X
- X if (opterr)
- X {
- X (void)write(2, a0, strlen(a0));
- X (void)write(2, errors[e], strlen(errors[e]));
- X eend[0] = c;
- X (void)write(2, eend, strlen(eend));
- X }
- X#else
- X static char *errors[] = {
- X "%s: Illegal option -- %c\n",
- X "%s: option requires an argument -- %c\n"
- X };
- X
- X if (opterr)
- X fprintf(stderr, errors[e], a0, c);
- X#endif
- X}
- @//E*O*F getopt.c//
- if test 3739 -ne "`wc -c <'getopt.c'`"; then
- echo shar: error transmitting "'getopt.c'" '(should have been 3739 characters)'
- fi
- fi # end of overwriting check
- echo shar: extracting "'makefile'" '(241 characters)'
- if test -f 'makefile' ; then
- echo shar: will not over-write existing file "'makefile'"
- else
- sed 's/^X//' >makefile <<'@//E*O*F makefile//'
- Xall: cut paste
- X
- X
- Xpaste: paste.o spaste.o getopt.o
- X cc -o paste paste.o spaste.o getopt.o
- X
- Xcut: cut.o getopt.o
- X cc -o cut cut.o getopt.o
- X
- Xlint: lint_cut lint_paste
- X
- Xlint_cut:
- X lint cut.c getopt.c
- X
- Xlint_paste:
- X lint paste.c spaste.c getopt.c
- X
- @//E*O*F makefile//
- if test 241 -ne "`wc -c <'makefile'`"; then
- echo shar: error transmitting "'makefile'" '(should have been 241 characters)'
- fi
- fi # end of overwriting check
- echo shar: extracting "'paste.1'" '(2608 characters)'
- if test -f 'paste.1' ; then
- echo shar: will not over-write existing file "'paste.1'"
- else
- sed 's/^X//' >paste.1 <<'@//E*O*F paste.1//'
- X.TH PASTE 1
- X.SH NAME
- Xpaste \- merge same lines of several files or subsequent lines of one file
- X.SH SYNOPSIS
- X\f3paste \fPfile1 file2 .\|.\|.
- X.br
- X\f3paste \-d\fP\|list file1 file2 .\|.\|.
- X.br
- X\f3paste \-s [\-d\fP\|list\|\f3] \fPfile1 file2 .\|.\|.
- X.SH DESCRIPTION
- XIn the first two forms,
- X.I paste\^
- Xconcatenates corresponding lines of the given input
- Xfiles
- X.IR file1 ,
- X.IR file2 ,
- Xetc.
- XIt treats each file as a column or columns
- Xof a table and pastes them together horizontally
- X(parallel merging).
- XIf you will, it is
- Xthe counterpart of
- X.IR cat (1)
- Xwhich concatenates vertically, i.e.,
- Xone file after the other.
- XIn the last form above,
- X.I paste\^
- Xreplaces the function of an older command with the same name
- Xby combining subsequent lines of the input file (serial merging).
- XIn all cases,
- Xlines are glued together with the
- X.I tab\^
- Xcharacter,
- Xor with characters from an optionally specified
- X.IR list .
- XOutput is to the standard output, so it can be used as
- Xthe start of a pipe,
- Xor as a filter,
- Xif \f3\-\fP is used in place of a file name.
- X.PP
- XThe meanings of the options are:
- X.TP
- X.B "\-d"
- XWithout this option,
- Xthe new-line characters of each but the last file
- X(or last line in case of the
- X.B \-s
- Xoption)
- Xare replaced
- Xby a
- X.I tab\^
- Xcharacter.
- XThis option allows replacing the
- X.I tab\^
- Xcharacter by one or more alternate characters (see below).
- X.TP
- X.I "list\^"
- XOne or more characters immediately following
- X.B \-d
- Xreplace the default
- X.I tab\^
- Xas the line concatenation character.
- XThe list is used circularly, i.e., when exhausted, it is reused.
- XIn parallel merging (i.e., no
- X.B \-s
- Xoption),
- Xthe lines from the last file are always terminated with a new-line character,
- Xnot from the
- X.IR list .
- XThe list may contain the special escape sequences:
- X.B \en
- X(new-line),
- X.B \et
- X(tab),
- X.B \e\e
- X(backslash), and
- X.B \e0
- X(empty string, not a null character).
- XQuoting may be necessary, if characters have special meaning to the shell
- X(e.g., to get one backslash, use
- X.I \-d\|"\e\e\e\e\^"
- X).
- X.TP
- X.B "\-s"
- XMerge subsequent lines rather than one from each input file.
- XUse
- X.I tab\^
- Xfor concatenation, unless a
- X.I list\^
- Xis specified
- Xwith
- X.B \-d
- Xoption.
- XRegardless of the
- X.IR list ,
- Xthe very last character of the file is forced to be a new-line.
- X.TP
- X.B "\-"
- XMay be used in place of any file name,
- Xto read a line from the standard input.
- X(There is no prompting).
- X.SH EXAMPLES
- X.TP 15m
- Xls \|\(bv\| paste \|\-d" " \|\-
- Xlist directory in one column
- X.TP
- Xls \|\(bv\| paste \|\- \|\- \|\- \|\-
- Xlist directory in four columns
- X.TP
- Xpaste \|\-s \|\-d"\e\|t\e\|n" \|file
- Xcombine pairs of lines into lines
- X.SH "SEE ALSO"
- Xcut(1), grep(1), pr(1).
- @//E*O*F paste.1//
- if test 2608 -ne "`wc -c <'paste.1'`"; then
- echo shar: error transmitting "'paste.1'" '(should have been 2608 characters)'
- fi
- fi # end of overwriting check
- echo shar: extracting "'paste.c'" '(4780 characters)'
- if test -f 'paste.c' ; then
- echo shar: will not over-write existing file "'paste.c'"
- else
- sed 's/^X//' >paste.c <<'@//E*O*F paste.c//'
- X/*
- X * A version of paste. This is compatable with AT&T paste command SVR2.
- X *
- X * John Weald
- X *
- X */
- X#include <stdio.h>
- X
- X#define MAXLINE 1024 /* Max. allowed line length */
- X#define MAXFILES 12 /* Max. number of input files */
- X
- Xextern void exit();
- X
- Xmain(argc, argv)
- Xint argc;
- Xchar *argv[];
- X{
- X extern int optind;
- X extern char *optarg;
- X
- X int c; /* For getopt() */
- X char conchars[MAXFILES]; /* The concatination characters */
- X int nconchars = 1; /* The number of conchars[] */
- X int serial = 0; /* True if old type paste "-s" */
- X
- X conchars[0] = '\t';
- X
- X while ((c = getopt(argc, argv, "sd:")) != EOF)
- X {
- X switch(c)
- X {
- X case 's':
- X /* Concatinate the same file serially */
- X serial++;
- X break;
- X
- X case 'd':
- X /* Use other than a single tab */
- X nconchars = setconcat(conchars, optarg);
- X break;
- X
- X default:
- X /* Does not return */
- X prusage();
- X }
- X }
- X
- X
- X if (serial)
- X spaste(&argv[optind], conchars, nconchars);
- X else
- X paste(&argv[optind], conchars, nconchars);
- X exit(0);
- X/* NOTREACHED */
- X}
- X
- X
- X
- X/*
- X * paste()
- X *
- X * Do the actual paste.
- X */
- Xpaste(files, con, ncons)
- Xchar *files[]; /* Null terminated list of input files */
- Xchar con[]; /* The concatination characters */
- Xchar ncons; /* The number of above */
- X{
- X char ibuf[MAXLINE+1]; /* The input buffer */
- X char obuf[MAXLINE]; /* The output buffer */
- X register char *iptr = ibuf;
- X register char *optr = obuf;
- X FILE *fps[MAXFILES]; /* One for each open file */
- X int f; /* Number of files opened */
- X int allfiles; /* Ditto */
- X int inc; /* True if concat. char. == '\0'*/
- X int ocount; /* Output buffer char. count */
- X char c; /* The current concat. char */
- X int i;
- X
- X /*
- X * Open all the input files, any filename of '-' means
- X * the standard input. No file name means standard input.
- X */
- X for (f = 0; files[f] != (char *)NULL; f++)
- X {
- X if (*files[f] == '-')
- X fps[f] = stdin;
- X else if ((fps[f] = fopen(files[f], "r")) == (FILE *)NULL)
- X {
- X fprintf(stderr, "Failed to open file %s\n", files[f]);
- X exit(1);
- X }
- X if (f >= MAXFILES)
- X {
- X fprintf(stderr,
- X "Too many files. Maximum allowed is %d\n", MAXFILES);
- X exit(1);
- X }
- X }
- X if (files[0] == (char *)NULL)
- X {
- X fps[0] = stdin;
- X f++;
- X }
- X
- X /*
- X * Read all lines until no more lines in any file.
- X */
- X allfiles = f;
- X while (f)
- X {
- X optr = obuf;
- X ocount = 0;
- X /*
- X * Join lines from all files.
- X *
- X * The concatination character may be '\0' which
- X * means no character. The variable inc is an indication
- X * of the concatination character being '\0', we need to
- X * if there is a concatination character to move up the
- X * output buffer.
- X *
- X * The concatination characters are used in a round robin
- X * list.
- X */
- X
- X for (inc = 0, i = 0; i < allfiles; i++)
- X {
- X iptr = ibuf;
- X optr += inc;
- X /* To save repeated evaluation */
- X c = con[i % ncons];
- X inc = c == '\0' ? 0 : 1;
- X
- X if (fps[i] == (FILE *)NULL)
- X {
- X /* No more lines in this file. */
- X
- X *optr = c;
- X continue;
- X }
- X if (fgets(ibuf, sizeof(ibuf), fps[i]) == (char *)NULL)
- X {
- X /* Reached EOF - finished with the file */
- X (void)fclose(fps[i]);
- X fps[i] = (FILE *)NULL;
- X *optr = c;
- X f--;
- X continue;
- X }
- X
- X /*
- X * Replace the newline with the concatination character.
- X * There is no need to look for end-of-string since
- X * we know that
- X * a) if ibuf is full to the max, then we will
- X * overflow obuf before we hit the end of ibuf.
- X * b) if ibuf is not full, then it must contain a
- X * a newline character, but may or may not
- X * fit into obuf.
- X */
- X for (; *iptr != '\n'; ocount++)
- X {
- X /* Need space for trailing null */
- X if (ocount >= sizeof(obuf) - 1)
- X {
- X fprintf(stderr, "Output line too long, maximum length is %d.\n", MAXLINE);
- X exit(1);
- X }
- X *optr++ = *iptr++;
- X }
- X *optr = c;
- X
- X }
- X if (f)
- X {
- X *optr = '\0';
- X puts(obuf);
- X }
- X }
- X}
- X
- X
- X/*
- X * setconcat()
- X *
- X * Parse the concatination characters and place them in the array c.
- X * Return the number of concatination characters.
- X *
- X * Specials are:
- X * \n - Newline
- X * \t - Tab (default)
- X * \ - Backslash
- X * \0 - No concatination character
- X */
- Xstatic int
- Xsetconcat(c, in)
- Xchar *c;
- Xchar *in;
- X{
- X int i; /* The number seen so far */
- X
- X for (i = 0; *in != '\0'; in++, c++, i++)
- X {
- X if (i > MAXFILES)
- X {
- X fprintf(stderr, "Too many concatination characters, maximum allowed is %d\n", MAXFILES);
- X exit(1);
- X }
- X if (*in != '\\')
- X {
- X *c = *in;
- X continue;
- X }
- X in++;
- X switch (*in)
- X {
- X case 'n':
- X *c = '\n';
- X break;
- X case 't':
- X *c = '\t';
- X break;
- X case '0':
- X *c = '\0';
- X break;
- X default:
- X /* Includes '\\' */
- X *c = *in;
- X break;
- X }
- X }
- X return(i);
- X}
- X
- Xstatic
- Xprusage()
- X{
- X fprintf(stderr, "USAGE: paste [-s] [-d<list>] files\n");
- X exit(1);
- X}
- @//E*O*F paste.c//
- if test 4780 -ne "`wc -c <'paste.c'`"; then
- echo shar: error transmitting "'paste.c'" '(should have been 4780 characters)'
- fi
- fi # end of overwriting check
- echo shar: extracting "'spaste.c'" '(2641 characters)'
- if test -f 'spaste.c' ; then
- echo shar: will not over-write existing file "'spaste.c'"
- else
- sed 's/^X//' >spaste.c <<'@//E*O*F spaste.c//'
- X/*
- X * Serially paste a file together
- X *
- X * John Weald
- X */
- X#include <stdio.h>
- X
- Xextern void exit();
- X
- X
- Xspaste(files, c, n)
- Xchar *files[]; /* Null terminate list of input files */
- Xchar c[]; /* The concatintaion characters */
- Xint n; /* The number of above */
- X{
- X int i;
- X FILE *fp;
- X
- X if (files[0] == (char *)NULL)
- X {
- X spfile(stdin, c, n);
- X return;
- X }
- X
- X for (i = 0; files[i] != (char *)NULL; i++)
- X {
- X if (*files[i] == '-')
- X fp = stdin;
- X else if ((fp = fopen(files[i], "r")) == (FILE *)NULL)
- X {
- X fprintf(stderr, "Failed to open file %s\n", files[i]);
- X exit(1);
- X }
- X spfile(fp, c, n);
- X (void)fclose(fp);
- X }
- X}
- X
- X/*
- X * Do the actual paste of a stream.
- X *
- X * The method here is to read in the stream and replace all newline
- X * characters with concatintaion characters.
- X * Output occurs after each chuck is parsed, or if the concatination character
- X * is the null seperator (otherwise puts() would screw up on whole chunk).
- X *
- X * The stream is read in BUFSIZ chunks using fread. The input buffer is one
- X * larger than read, so that it can be null terminated.
- X *
- X * When we read in each chunk we must check if it needs to be joined to the
- X * previous one i.e. the last character on the last chunk was a newline.
- X */
- Xstatic
- Xspfile(fp, con, ncons)
- XFILE *fp; /* serially paste this stream */
- Xchar con[]; /* The concatintaion characters */
- Xint ncons; /* The number of above */
- X{
- X char *pstart; /* The start of the string */
- X char *ptr; /* Walks down the stream */
- X char buf[BUFSIZ + 1]; /* To ensure null termination */
- X int n; /* Number of bytes read with fread() */
- X int k = 0; /* Index into concatination character array */
- X int join; /* Join this chunk to the next? */
- X char last; /* The very last character looked at. */
- X
- X
- X join = 0;
- X while ((n = fread(buf, sizeof(char), sizeof(buf) - 1, fp)) != 0)
- X {
- X if (join)
- X {
- X /* Join with last chunk */
- X putchar(con[k]);
- X k = (k + 1) % ncons;
- X join = 0;
- X }
- X /* Join to next chunk? */
- X if (buf[n-1] == '\n')
- X {
- X join++;
- X /* Ignore the newline */
- X n--;
- X }
- X
- X /* ensure null terminated buffer */
- X buf[n] = '\0';
- X
- X
- X /*
- X * walk thru this chunk
- X * replace all newlines with the next concat. char.
- X */
- X for (pstart = ptr = buf; *ptr != '\0'; ptr++)
- X {
- X if (*ptr == '\n')
- X {
- X *ptr = con[k];
- X if (con[k] == '\0')
- X {
- X fputs(pstart, stdout);
- X pstart = ptr + 1;
- X }
- X k = (k + 1) % ncons;
- X }
- X }
- X fputs(pstart, stdout);
- X
- X last = *(ptr - 1);
- X }
- X
- X /*
- X * Maybe they asked for the newline as the
- X * concatination char. We would hate to give them two newlines
- X * in a row.
- X */
- X if (last != '\n')
- X putchar('\n');
- X}
- @//E*O*F spaste.c//
- if test 2641 -ne "`wc -c <'spaste.c'`"; then
- echo shar: error transmitting "'spaste.c'" '(should have been 2641 characters)'
- fi
- fi # end of overwriting check
- echo shar: "End of shell archive."
- exit 0
-